/**
 * Class to manage WebGL methods.
 */

/**
 * Constructor
 * @param canvasId
 * @param vertexShaderId
 * @param fragmentShaderId
 */
ns.WebGLmanager = function(canvasId, vertexShaderId, fragmentShaderId) {
	this.canvasId = canvasId;
	this.vertexShaderId = vertexShaderId;
	this.fragmentShaderId = fragmentShaderId;
	this.gl = null;
	this.shaderProgram = null;
};

/**
 * Initializes the WebGL context.
 */
ns.WebGLmanager.prototype._initContext = function() {
	var canvas = document.getElementById(this.canvasId);
	try {
		this.gl = canvas.getContext("experimental-webgl");
		if(this.gl == null){
			throw "Could not initialise WebGL";
		}
	} catch (e) {
		throw "[ERROR] Could not initialise WebGL.";
	}
};

/**
 * Retrieves a shader
 * @param shaderId
 * @returns
 */
ns.WebGLmanager.prototype._getShader = function(shaderId) {
	var shaderScript = document.getElementById(shaderId);
	if (!shaderScript) {
		throw "[ERROR] No shader script in element " + shaderId;
	}

	var shaderSource = "";
	var currentChild = shaderScript.firstChild;

	while (currentChild) {
		if (currentChild.nodeType == currentChild.TEXT_NODE) {
			shaderSource += currentChild.textContent;
		}

		currentChild = currentChild.nextSibling;
	}

	var shader;
	if (shaderScript.type == "x-shader/x-fragment") {
		shader = this.gl.createShader(this.gl.FRAGMENT_SHADER);
	} else if (shaderScript.type == "x-shader/x-vertex") {
		shader = this.gl.createShader(this.gl.VERTEX_SHADER);
	} else {
		throw "[ERROR] Undefined shader type.";
	}

	this.gl.shaderSource(shader, shaderSource);
	this.gl.compileShader(shader);

	if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
		throw "[ERROR] Shader compilation error. "
				+ this.gl.getShaderInfoLog(shader);
	}

	return shader;
};

/**
 * Initializes the WebGL shaders
 */
ns.WebGLmanager.prototype._initShaders = function() {
	var fragmentShader = this._getShader(this.fragmentShaderId);
	var vertexShader = this._getShader(this.vertexShaderId);

	this.shaderProgram = this.gl.createProgram();
	this.gl.attachShader(this.shaderProgram, vertexShader);
	this.gl.attachShader(this.shaderProgram, fragmentShader);
	this.gl.linkProgram(this.shaderProgram);

	if (!this.gl.getProgramParameter(this.shaderProgram, this.gl.LINK_STATUS)) {
		throw "[ERROR] Could not initialise shaders";
	}

	this.gl.useProgram(this.shaderProgram);
};

/**
 * Initializes WebGL
 */
ns.WebGLmanager.prototype.init = function() {
	this._initContext();
	this._initShaders();
};

/**
 * Retrieves the WebGL context
 * @returns
 */
ns.WebGLmanager.prototype.getContext = function() {
	return this.gl;
};

/**
 * Retrieves the shader program
 * @returns
 */
ns.WebGLmanager.prototype.getShaderProgram = function() {
	return this.shaderProgram;
};